package com.liuqianfei.markme.core;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * new Token(type, tag, nesting) Create new token and fill passed properties.
 * 
 * @author liuqianfei
 **/
public class Token
{
    /**
     * Type of the token (string, e.g. "paragraph_open")
     **/
    public String type;
    
    /**
     * html tag name, e.g. "p"
     */
    public String tag;
    
    /**
     * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`
     */
    public Map<String, String> attrs;
    
    /**
     * Source map info. Format: `[ line_begin, line_end ]`
     */
    public int[] map = new int[2];
    
    /**
     * Level change (number in {-1, 0, 1} set), where:
     * <ul>
     *  <li>`1` means the tag is opening</li>
     *  <li>`0` means the tag is self-closing</li>
     *  <li>`-1` means the tag is closing</li>
     * </ul>
     */
    public int nesting;
    
    /**
     * nesting level, the same as `state.level`
     */
    public int level = 0;
    
    /**
     * An array of child nodes (inline and img tokens)
     */
    public List<Token> children;
    
    /**
     * In a case of self-closing tag (code, html, fence, etc.),
     * it has contents of this tag.
     */
    public String content = "";
    
    /**
     * '*' or '_' for emphasis, fence string for fence, etc.
     */
    public String markup = "";
    
    /**
     * fence infostring
     */
    public String info = "";
    
    /**
     * A place for plugins to store an arbitrary data
     */
    public Object meta;
    
    /**
     * True for block-level tokens, false for inline tokens.
     * Used in renderer to calculate line breaks
     */
    public boolean block = false;
    
    /**
     * If it's true, ignore this element when rendering. Used for tight lists
     * to hide paragraphs.
     */
    public boolean hidden = false;
    
    public Token(){}
    
    public Token(String type, String tag, int nesting)
    {
        this.type = type;
        this.tag = tag;
        this.nesting = nesting;
    }

    /**
     * Token.attrIndex(name) -> Number
     *
     * Search attribute index by name.
     **/
    public int attrIndex(String name)
    {
        Map<String, String> attrs;
        int i = 0;

        if (null == this.attrs || this.attrs.size() == 0)
            return -1;

        attrs = this.attrs;

        for (String key : attrs.keySet())
        {
            if (null != key && key.equals(name))
                return i;

            i++;
        }

        return -1;
    }
    
    /**
     * Add `[ name, value ]` attribute to list. Init attrs if necessary
     */
    public void pushAttr(Map<String, String> attrData)
    {
        if (null == this.attrs)
            this.attrs = new HashMap<>();

        this.attrs.putAll(attrData);
    }
    
    /**
     * Set `name` attribute to `value`. Override old value if exists.
     */
    public void setAttr(String name, String value)
    {
        if (null == this.attrs)
            this.attrs = new HashMap<>();

        this.attrs.put(name, value);
    }
    
    /**
     * Join value to existing attribute via space. Or create new attribute if not
     * exists. Useful to operate with token classes.
     */
    public void joinAttr(String name, String value)
    {
        if (null == this.attrs)
        {
            this.attrs = new HashMap<>();
            this.attrs.put(name, value);
        }
        else if (!this.attrs.containsKey(name))
        {
            this.attrs.put(name, value);
        }
        else
        {
            String v = this.attrs.get(name);
            v += " " + value;
            this.attrs.put(name, v);
        }
    }
}
